package com.tiancheng.trade.order.channel.gaocheng;

import com.tiancheng.trade.commom.core.exception.BusinessException;
import com.tiancheng.trade.commom.core.exception.error.BusinessErrorInfoEnum;
import com.tiancheng.trade.commom.web.model.request.RefundDTO;
import com.tiancheng.trade.order.bo.SubOrderRefundTotalBo;
import com.tiancheng.trade.order.channel.AbstractPayChannel;
import com.tiancheng.trade.order.enums.RefundStatusEnum;
import com.tiancheng.trade.order.model.Order;
import com.tiancheng.trade.order.model.RefundOrders;
import com.tiancheng.trade.order.model.RefundOrdersDetail;
import com.tiancheng.trade.order.model.SubOrder;
import com.tiancheng.trade.order.vo.open.order.OpenRefundVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 高诚-支付渠道
 *
 * @author likailun
 * @date 2021/4/20
 */
@Slf4j
@Service
public class GcPayChannel extends AbstractPayChannel {


    @Override
    public RefundOrders generateRefunds(OpenRefundVO refundVO, Order order) {
        String[] subOrderIds = refundVO.getSubOrders().stream().map(OpenRefundVO.SubOrder::getSubOrderId).toArray(String[]::new);
        List<SubOrder> subOrders = subOrderService.findCanRefund(refundVO.getOrderId(), subOrderIds);

        // 子订单新提交的退款
        Map<String, Integer> applyRefundMap = refundVO.getSubOrders().stream().collect(Collectors.toMap(OpenRefundVO.SubOrder::getSubOrderId, x -> x.getRefundAmount() != null ? x.getRefundAmount() : 0));
        // 子订单所有退款汇总金额（包含本次提交的退款金额），包含已存在的退款记录状态为：IG、SC
        Map<String, SubOrderRefundTotalBo> refundTotalMap = this.checkRefundAmount(order, subOrders, applyRefundMap);
        String paymentId = orderIdHelper.getRefundPaymentId(order.getOrderSource(), refundVO.getUid());
        List<RefundOrdersDetail> refundOrdersDetails = new ArrayList<>();
        Integer suffix=1;
        for (OpenRefundVO.SubOrder refundVOSubOrder : refundVO.getSubOrders()) {
            SubOrder subOrder = subOrders.stream().filter(s->s.getSubOrderId().equals(refundVOSubOrder.getSubOrderId())).findFirst().get();
            RefundOrdersDetail refundOrdersDetail = new RefundOrdersDetail();
            refundOrdersDetail.setUid(refundVO.getUid());
            refundOrdersDetail.setRefundId(refundVO.getRefundId());
            refundOrdersDetail.setSubRefundId(refundVOSubOrder.getSubRefundId());
            refundOrdersDetail.setPaymentId(paymentId);
            refundOrdersDetail.setSubPaymentId((paymentId + String.format("%02d", suffix)));
            suffix++;
            refundOrdersDetail.setPayFlowId(order.getFlowId());
            refundOrdersDetail.setSubPayFlowId(subOrder.getSubFlowId());
            refundOrdersDetail.setOrderId(subOrder.getOrderId());
            refundOrdersDetail.setSubOrderId(subOrder.getSubOrderId());
            refundOrdersDetail.setOrderSource(subOrder.getOrderSource());
            refundOrdersDetail.setMerchantCode(subOrder.getMerchantCode());
            refundOrdersDetail.setMerchantName(subOrder.getMerchantName());
            refundOrdersDetail.setProductCode(subOrder.getProductCode());
            refundOrdersDetail.setProductName(subOrder.getProductName());
            // 退款金额，如果未提交，默认使用子订单应收金额
            // 申请退款金额
            Integer refundApplyAmount = null;
            if (applyRefundMap.get(subOrder.getSubOrderId()) != 0) {
                //如果业务侧提交了退款金额
                refundApplyAmount = applyRefundMap.get(subOrder.getSubOrderId());
            } else {
                // 业务侧未提交子订单退款金额
                // 申请退款金额=订单金额
                refundApplyAmount = subOrder.getSubOrderAmount();
                log.info("子订单未提交退款金额，子订单：{}，提交高诚：{}", subOrder.getSubOrderId(), refundApplyAmount);
            }

            //判断子订单累计申请退款的金额是否等于子订单应收金额,相等则说明全额退款了（子订单最后一次申请退款）
            SubOrderRefundTotalBo totalBo = refundTotalMap.get(subOrder.getSubOrderId());
            int divide = 0;
            log.info("子订单:{} 应收金额：{}，总退款申请金额（包含本次提交的)为：{} ，退款成功分摊的平台优惠总额累计：{}", subOrder.getSubOrderId(), subOrder.getSubOrderAmount(), totalBo.getTotalApplyAmount(), totalBo.getTotalPlatformDiscount());
            if (totalBo.getTotalApplyAmount().intValue() == subOrder.getSubOrderAmount().intValue()) { //totalBo.getTotalApplyAmount() 总退款申请金额（包含本次提交的）
                divide = subOrder.getPlatformDiscount() - totalBo.getTotalPlatformDiscount();//子订单的平台优惠金额-子订单退款成功已经分摊的平台优惠总额累计
            } else {
                //计算子订单退款平台优惠金额=(申请退款金额/子订单应收金额)*子订单优惠金额
                divide = BigDecimal.valueOf(refundApplyAmount).divide(BigDecimal.valueOf(subOrder.getSubOrderAmount()), 10, BigDecimal.ROUND_DOWN).multiply(BigDecimal.valueOf(subOrder.getPlatformDiscount())).setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
            }
            log.info("子订单退款平台优惠金额为：{}", divide);
            refundOrdersDetail.setDiscount(divide);
            refundOrdersDetail.setPlatformDiscount(divide);
            refundOrdersDetail.setRefundApplyAmount(refundApplyAmount);
            refundOrdersDetail.setRefundAmount(refundApplyAmount - divide); // 实际退款金额=申请退款金额-应退优惠
            refundOrdersDetail.setSubOrderAmount(subOrder.getSubOrderAmount());
            refundOrdersDetail.setSubOrderPayAmount(subOrder.getPayAmount());
            refundOrdersDetail.setRefundStatus(RefundStatusEnum.ing.getCode());
            refundOrdersDetail.setRefundReason(refundVO.getRefundReason());
            refundOrdersDetail.setCreatedDt(refundVO.getCreateTime());
            refundOrdersDetail.setSubOrderStatus(subOrder.getSubOrderStatus());
            refundOrdersDetails.add(refundOrdersDetail);
        }

        // 总退款单
        final RefundOrders refundOrders = new RefundOrders();
        refundOrders.setRefundId(refundVO.getRefundId());
        refundOrders.setOrderId(refundVO.getOrderId());
        refundOrders.setPaymentId(paymentId);
        refundOrders.setPayFlowId(order.getFlowId());
        refundOrders.setUid(refundVO.getUid());
        refundOrders.setRefundApplyAmount(refundOrdersDetails.stream().mapToInt(RefundOrdersDetail::getRefundApplyAmount).sum());
        refundOrders.setRefundAmount(refundOrdersDetails.stream().mapToInt(RefundOrdersDetail::getRefundAmount).sum());
        refundOrders.setRefundStatus(RefundStatusEnum.ing.getCode());
        refundOrders.setRefundReason(refundVO.getRefundReason());
        refundOrders.setCreatedDt(LocalDateTime.now());
        refundOrders.setSubRefundOrders(refundOrdersDetails);
        return refundOrders;
    }


    @Override
    public RefundDTO createAndSubmit(OpenRefundVO refundVO, RefundOrders refundOrders) {
        final List<RefundOrdersDetail> refundOrdersDetails = refundOrders.getSubRefundOrders();
        RefundDTO refundDTO = new RefundDTO();
        refundDTO.setUid(refundVO.getUid());
        refundDTO.setPaymentId(refundOrdersDetails.get(0).getPaymentId());
        refundDTO.setPayFlowId(refundOrdersDetails.get(0).getPayFlowId());
        refundDTO.setAmount(refundOrdersDetails.stream().mapToInt(RefundOrdersDetail::getRefundApplyAmount).sum());
        refundDTO.setReason(refundVO.getRefundReason());
        refundDTO.setOrderAmount(refundOrdersDetails.stream().mapToInt(RefundOrdersDetail::getSubOrderAmount).sum());
        refundDTO.setDiscount(refundOrdersDetails.stream().mapToInt(RefundOrdersDetail::getPlatformDiscount).sum());
        refundDTO.setSubOrders(new ArrayList<>());

        refundOrdersDetails.forEach(refund -> {
            RefundDTO.SubOrderRefundDTO subOrderRefundDTO = new RefundDTO.SubOrderRefundDTO();
            subOrderRefundDTO.setSubOrderId(refund.getSubOrderId());
            subOrderRefundDTO.setSubPayFlowId(refund.getSubPayFlowId());
            subOrderRefundDTO.setSubPaymentId(refund.getSubPaymentId());
            subOrderRefundDTO.setAmount(refund.getRefundApplyAmount());
            subOrderRefundDTO.setOrderAmount(refund.getSubOrderAmount());
            subOrderRefundDTO.setDiscount(refund.getPlatformDiscount());
            refundDTO.getSubOrders().add(subOrderRefundDTO);
        });
        return refundDTO;
    }

    /**
     * 检查子订单的退款金额
     *
     * @param order         总订单
     * @param subOrders       申请退款子订单
     * @param submitRefundMap 申请退款的子订单退款信息
     * @return 已存在退款的订单信息(不包含本次提交的退款)
     * @throws BusinessException
     */
    @Override
    protected Map<String, SubOrderRefundTotalBo> checkRefundAmount(Order order, List<SubOrder> subOrders, Map<String, Integer> submitRefundMap) throws BusinessException {
        // 子订单已经退的款
        String[] subOrderIds = subOrders.stream().map(SubOrder::getSubOrderId).toArray(String[]::new);
        List<SubOrderRefundTotalBo> subOrderRefunds = refundOrdersDetailMapper.sumForSubOrder(order.getOrderId(), subOrderIds);
        // 判断支付金额是否大于退款金额
        Map<String, SubOrderRefundTotalBo> refundTotalMap = new HashMap<>();
        for (SubOrder subOrder : subOrders) {
            int refundTotal = 0;
            int refundApplyTotal = 0; //子订单已申请退款总金额
            List<SubOrderRefundTotalBo> subRefund = subOrderRefunds.stream().filter(s -> s.getSubOrderId().equals(subOrder.getSubOrderId())).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(subRefund)) {
                // 该子订单已有退款状态为“IG”、“SC”的退款记录
                refundTotal += subRefund.get(0).getTotal();
                refundApplyTotal+=subRefund.get(0).getTotalApplyAmount();
            } else {
                // 不存在退款记录
                subRefund.add(new SubOrderRefundTotalBo(subOrder.getSubOrderId(), 0, 0,0,0));
            }
            if (submitRefundMap.get(subOrder.getSubOrderId()) != 0) {
                // 业务系统提交了退款金额
                refundTotal += submitRefundMap.get(subOrder.getSubOrderId()).intValue();
                refundApplyTotal+=submitRefundMap.get(subOrder.getSubOrderId()).intValue();
            } else {
                // 没有提交退款金额
                refundTotal += subOrder.getSubOrderAmount();
                refundApplyTotal+= subOrder.getSubOrderAmount();
            }
            // 判断总退款金额不超过子订单金额
            BusinessErrorInfoEnum.ORDER_REFUND_AMOUNT_SHORT.assertIsTrue(subOrder.getSubOrderAmount() >= refundApplyTotal);
            // 设置子订单的总退款金额（包含本次提交的）
            subRefund.get(0).setTotal(refundTotal);
            subRefund.get(0).setTotalApplyAmount(refundApplyTotal);//总退款申请金额（包含本次提交的）
            refundTotalMap.put(subOrder.getSubOrderId(), subRefund.get(0));
        }
        return refundTotalMap;
    }

    /**
     * 计算应该向渠道发起的退款金额
     *
     * @param actualRefundAmount 退到用的金额
     * @param order              主订单信息
     * @return
     */
    private int getChannelApplyRefund(int actualRefundAmount, Order order) {
        return actualRefundAmount;
    }
}
